package com.longxiao.service;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.longxiao.entity.Course;
import com.longxiao.entity.CourseChapter;
import com.longxiao.entity.CourseChapterDetail;
import com.longxiao.enums.ResultCode;
import com.longxiao.enums.SysConfigKey;
import com.longxiao.exception.LXException;
import com.longxiao.mapper.CourseChapterDetailMapper;
import com.longxiao.mapper.CourseChapterMapper;
import com.longxiao.mapper.CourseMapper;

@Service("courseService")
public class CourseService {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Resource
	private CourseMapper courseMapper;
	@Resource
	private CourseChapterMapper courseChapterMapper;
	@Resource
	private CourseChapterDetailMapper courseChapterDetailMapper;
	@Resource
	private SysConfigService sysConfigService;
	
	public boolean addCourse(Course course) throws Exception {
		logger.info("增加课程信息：{}",JSONObject.toJSONString(course));
		if(this.getCourseByName(course.getName()) != null) {
			throw new Exception("课程信息已存在");
		}
		return courseMapper.insertSelective(course) > 0;
	}
	/**
	 * 添加课程章节基本信息
	 * @param chapter
	 * @return
	 * @throws Exception 
	 */
	public CourseChapter addChapter(CourseChapter chapter) throws Exception {
		logger.info("添加课程章节基本信息：{}",JSONObject.toJSON(chapter));
		Course course = courseMapper.selectByPrimaryKey(chapter.getCourseId());
		if(course == null) {
			throw new Exception("课程信息不存在，添加失败！");
		}
		CourseChapter existsChapter = courseChapterMapper.selectByName(chapter.getName());
		if(existsChapter != null) {
			throw new Exception("章节信息已存在，添加失败！");
		}
		if (courseChapterMapper.insertSelective(chapter) > 0) {
			return chapter;
		} else {
			throw new Exception("插入章节信息失败");
		}
	}
	/**
	 * 更新课程章节基本信息
	 * @param chapter
	 * @return
	 * @throws Exception
	 */
	public boolean updateChapter(CourseChapter chapter) throws Exception {
		logger.info("更新课程章节基本信息：{}",JSONObject.toJSON(chapter));
		Course course = courseMapper.selectByPrimaryKey(chapter.getCourseId());
		if(course == null) {
			throw new Exception("课程信息不存在，更新失败！");
		}
		return courseChapterMapper.updateByPrimaryKeySelective(chapter) > 0;
	}
	
	public List<Course> getCourseList(Course course,int offset,int rows) {
		return courseMapper.getCourseList(course, offset, rows);
	}
	
	public int countCourseList(Course course) {
		return courseMapper.countCourseList(course);
	}
	
	public Course getCourseByName(String name) {
		return courseMapper.getCourseByName(name);
	}
	
	public boolean updateCourse(Course record) {
		return courseMapper.updateByPrimaryKeySelective(record) > 0;
	}
	
	public Course getCourseById(Integer courseId) {
		return courseMapper.selectByPrimaryKey(courseId);
	}
	
	public List<CourseChapter> getCourseChapterList(Integer courseId) {
		return courseChapterMapper.selectByCourseId(courseId);
	}
	
	public CourseChapter getCourseChapterById(Integer id) {
		return courseChapterMapper.selectByPrimaryKey(id);
	}
	
	/**
	 * 上传课件文件
	 * @param fileName
	 * @param chapterId
	 * @param os
	 * @return
	 * @throws LXException 
	 */
	@Transactional
	public String uploadCourseChapterFile(String fileName,Integer chapterId,InputStream fileContent) throws LXException {
		logger.info("上传章节课件文件：{}，{}",chapterId,fileName);
		CourseChapter chapter = courseChapterMapper.selectByPrimaryKey(chapterId);
		if(chapter == null) {
			throw new LXException(ResultCode.CHAPTER_NOT_EXISTS.getCode(), ResultCode.CHAPTER_NOT_EXISTS.getCn());
		}
		
		String prePath = sysConfigService.getValByKeyword(SysConfigKey.CHAPTER_FILE_LOCAL);
		String subPath = this.getSubPath(chapter);
		String httpPathPre = this.getPath(sysConfigService.getValByKeyword(SysConfigKey.CHAPTER_FILE_HTTP),subPath);
		
		String filePath = prePath + subPath;
		try {
			
			String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
			String httpName = UUID.randomUUID() + "." + ext;
			
			String zipUrl = this.uploadZip(filePath,httpPathPre,httpName,fileContent);
			chapter.setUrl(zipUrl);
			List<CourseChapterDetail> detailList = this.uploadDetail(filePath,httpPathPre,httpName,chapter);
			for(CourseChapterDetail detail : detailList) {
				courseChapterDetailMapper.insertSelective(detail);
			}
			this.courseChapterMapper.updateByPrimaryKeySelective(chapter);
			return zipUrl;
		} catch (Exception e) {
			logger.error(chapterId + "上传课件失败：" + e.getMessage(),e);
		}
		throw new LXException(ResultCode.FILE_UPLOAD_FAIL.getCode(), ResultCode.FILE_UPLOAD_FAIL.getCn());
	}
	
	private String getPath(String firstPath, String secondPath) {
		if(firstPath.endsWith("/")) {
			if(secondPath.startsWith("/")) {
				return firstPath + secondPath.substring(1);
			}
		} else {
			if(!secondPath.startsWith("/")) {
				return firstPath + "/" + secondPath;
			}
		}
		return firstPath + secondPath;
	}

	private String JPG = "JPG";
	private String TXT = "TXT";
	
	private List<CourseChapterDetail> uploadDetail(String filePathPre, String httpPathPre, String fileName,
			CourseChapter chapter) throws IOException, LXException {
		
		logger.info("上传课程明细信息：{}",chapter.getId());
		List<CourseChapterDetail> oldDetailList = courseChapterDetailMapper.selectByChapterId(chapter.getId());
		for(CourseChapterDetail oldDetail : oldDetailList) {
			courseChapterDetailMapper.deleteByPrimaryKey(oldDetail.getId());
		}
		List<CourseChapterDetail> detailList = new ArrayList<CourseChapterDetail>();
		ZipFile zipFile = new ZipFile(filePathPre + "/" + fileName,Charset.forName("GBK"));
		Map<String,CourseChapterDetail> detailDescMap = new HashMap<String,CourseChapterDetail>();
		Enumeration<ZipEntry> zipEntries = (Enumeration<ZipEntry>) zipFile.entries();
		int count = 1;
		while(zipEntries.hasMoreElements()) {
			ZipEntry zipEntry = zipEntries.nextElement();
			if(zipEntry.isDirectory()) {
				continue;
			}
			
			String absFileName = filePathPre + "/" + zipEntry.getName();
			absFileName = absFileName.replace("\\", "/");
			String absFilePath = this.getAbsPath(absFileName);
			
			InputStream is = new BufferedInputStream(zipFile.getInputStream(zipEntry));
			String name = this.getFileName(absFileName);
			String nameWithoutExt = name.substring(0, name.lastIndexOf("."));
			String ext = name.substring(name.lastIndexOf(".") + 1);
			String httpName = UUID.randomUUID() + "." + ext;
			is.mark(0);
			this.writeFile(absFilePath, httpName, is);
			
			String fileExt = this.getFileExt(name);
			if(JPG.equalsIgnoreCase(fileExt)) {
				CourseChapterDetail detail = new CourseChapterDetail();
				detail.setCourseChapterId(chapter.getId());
				detail.setCourseId(chapter.getCourseId());
				detail.setDetailName(name);
				count = this.getCount(nameWithoutExt, count++);
				detail.setDetailSeq(count);
				String httpUrl = this.getPath(httpPathPre, zipEntry.getName());
				detail.setDetailUrl(this.getAbsPath(httpUrl) + "/" + httpName);
				detail.setStatus((byte)1);
				detail.setCreatedTime(new Date());
				detailDescMap.put(nameWithoutExt, detail);
				detailList.add(detail);
			}
			
			if(TXT.equalsIgnoreCase(fileExt)) {
				is.reset();
				byte[] descContent = new byte[is.available()];
				is.read(descContent);
				CourseChapterDetail detail = detailDescMap.get(nameWithoutExt);
				if(detail != null) {
					detail.setDetailDesc(new String(descContent,"GBK"));
				}
			}
			try {
				is.close();
				is = null;
			} catch(Exception e){}
		}
		return detailList;
	}

	private int getCount(String str,int defaultValue) {
		String ptn = ".*?([0-9]+)";
		Pattern pattern = Pattern.compile(ptn);
		Matcher matcher = pattern.matcher(str);
		if(matcher.matches()) {
			return Integer.parseInt(matcher.group(1));
		}
		return defaultValue;
	}
	
	private String getFileExt(String name) {
		return name.substring(name.lastIndexOf(".") + 1);
	}

	private String getAbsPath(String absFileName) {
		return absFileName.substring(0, absFileName.lastIndexOf("/"));
	}
	
	private String getFileName(String absFileName) {
		return absFileName.substring(absFileName.lastIndexOf("/") + 1);
	}
	
	private String uploadZip(String filePathPre,String httpPathPre,String fileName,InputStream fileContent) throws IOException, LXException {
		
		
		this.writeFile(filePathPre,fileName, fileContent);
		
		return httpPathPre + fileName;
	}
	/*
	 * 向指定路径写入文件写入文件
	 */
	private void writeFile(String fileDirectory,String fileName,InputStream is) throws IOException, LXException {
		File directory = new File(fileDirectory);
		
		if(directory.exists() && directory.isDirectory()) {
			File file = new File(fileDirectory + "/" + fileName);
			OutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
			byte[] content = new byte[is.available()];
			is.read(content);
			fos.write(content, 0, content.length);
			fos.flush();
			fos.close();
			return ;
		}
		
		if(!directory.exists()) {
			if(directory.mkdirs()) {
				File file = new File(fileDirectory + "/" + fileName);
				OutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
				byte[] content = new byte[is.available()];
				is.read(content);
				fos.write(content, 0, content.length);
				fos.flush();
				fos.close();
				return ;
			}
		}
		
		throw new LXException(ResultCode.FILE_UPLOAD_FAIL.getCode(),ResultCode.FILE_UPLOAD_FAIL.getCn());
	}

	private String getSubPath(CourseChapter chapter) {
		return "/" + chapter.getCourseId() + "/" + chapter.getId();
	}
}
